"""MCP资源实现 - 定义MCP协议的资源"""

import asyncio
from typing import Dict, Any, List, Optional, Union
from datetime import datetime
from loguru import logger

import sys
from pathlib import Path

# 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))

from src.core.context_orchestrator import ContextOrchestrator


class MCPResources:
    """MCP资源集合 - 实现MCP协议的各种资源"""
    
    def __init__(self, orchestrator: ContextOrchestrator):
        self.orchestrator = orchestrator
        self.resources = {}
        self._register_default_resources()
        
        logger.info("MCP资源集合已创建")
    
    def _register_default_resources(self):
        """注册默认资源"""
        # 对话资源
        self.register_resource(
            "conversations",
            "对话记录",
            "用户的对话历史记录",
            "application/json",
            self._get_conversations
        )
        
        # 记忆资源
        self.register_resource(
            "memories",
            "记忆数据",
            "用户的记忆信息",
            "application/json",
            self._get_memories
        )
        
        # 知识文档资源
        self.register_resource(
            "documents",
            "知识文档",
            "用户上传的知识文档",
            "application/json",
            self._get_documents
        )
        
        # 向量嵌入资源
        self.register_resource(
            "embeddings",
            "向量嵌入",
            "文档和记忆的向量表示",
            "application/json",
            self._get_embeddings
        )
        
        # 知识图谱资源
        self.register_resource(
            "graph_data",
            "知识图谱",
            "概念和关系的图谱数据",
            "application/json",
            self._get_graph_data
        )
        
        # 用户上下文资源
        self.register_resource(
            "user_context",
            "用户上下文",
            "用户的完整上下文信息",
            "application/json",
            self._get_user_context
        )
        
        # 系统统计资源
        self.register_resource(
            "system_stats",
            "系统统计",
            "系统运行统计信息",
            "application/json",
            self._get_system_stats
        )
        
        # 健康状态资源
        self.register_resource(
            "health_status",
            "健康状态",
            "系统健康检查结果",
            "application/json",
            self._get_health_status
        )
    
    def register_resource(self, uri: str, name: str, description: str,
                         mime_type: str, handler: callable):
        """注册资源"""
        self.resources[uri] = {
            "uri": uri,
            "name": name,
            "description": description,
            "mimeType": mime_type,
            "handler": handler
        }
        
        logger.debug(f"注册资源: {uri}")
    
    def get_resource_list(self) -> List[Dict[str, Any]]:
        """获取资源列表"""
        return [
            {
                "uri": resource["uri"],
                "name": resource["name"],
                "description": resource["description"],
                "mimeType": resource["mimeType"]
            }
            for resource in self.resources.values()
        ]
    
    async def read_resource(self, uri: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """读取资源"""
        try:
            if uri not in self.resources:
                return {
                    "isError": True,
                    "content": [{
                        "type": "text",
                        "text": f"资源不存在: {uri}"
                    }]
                }
            
            resource = self.resources[uri]
            handler = resource["handler"]
            
            # 调用处理器
            result = await handler(params or {})
            
            return {
                "contents": [{
                    "uri": uri,
                    "mimeType": resource["mimeType"],
                    "text": self._format_resource_content(result)
                }]
            }
            
        except Exception as e:
            logger.error(f"读取资源失败: {uri} - {e}")
            return {
                "isError": True,
                "content": [{
                    "type": "text",
                    "text": f"资源读取失败: {str(e)}"
                }]
            }
    
    def _format_resource_content(self, content: Any) -> str:
        """格式化资源内容"""
        try:
            import json
            if isinstance(content, (dict, list)):
                return json.dumps(content, ensure_ascii=False, indent=2, default=str)
            else:
                return str(content)
        except Exception as e:
            logger.error(f"格式化资源内容失败: {e}")
            return str(content)
    
    # 资源处理器实现
    
    async def _get_conversations(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """获取对话资源"""
        try:
            user_id = params.get("user_id")
            limit = params.get("limit", 20)
            status = params.get("status")
            
            if not user_id:
                return {"error": "需要提供用户ID"}
            
            conversations = await self.orchestrator.conversation_manager.get_user_conversations(
                user_id, limit, status
            )
            
            # 获取每个对话的详细信息
            detailed_conversations = []
            for conv in conversations:
                conversation_id = conv.get("conversation_id")
                if conversation_id:
                    # 获取对话上下文
                    context = await self.orchestrator.conversation_manager.get_conversation_context(
                        conversation_id, 5  # 最近5条消息
                    )
                    
                    conv["recent_messages"] = context
                    detailed_conversations.append(conv)
            
            return {
                "user_id": user_id,
                "conversations": detailed_conversations,
                "total_count": len(detailed_conversations),
                "retrieved_at": datetime.utcnow().isoformat()
            }
            
        except Exception as e:
            logger.error(f"获取对话资源失败: {e}")
            return {"error": str(e)}
    
    async def _get_memories(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """获取记忆资源"""
        try:
            user_id = params.get("user_id")
            memory_type = params.get("memory_type")
            limit = params.get("limit", 50)
            
            if not user_id:
                return {"error": "需要提供用户ID"}
            
            # 获取不同类型的记忆
            memories = {}
            
            if not memory_type or memory_type == "short_term":
                short_term = await self.orchestrator.memory_manager.get_short_term_memories(
                    user_id, limit
                )
                memories["short_term"] = short_term
            
            if not memory_type or memory_type == "long_term":
                long_term = await self.orchestrator.memory_manager.get_long_term_memories(
                    user_id, limit
                )
                memories["long_term"] = long_term
            
            if not memory_type or memory_type == "semantic":
                semantic = await self.orchestrator.memory_manager.get_semantic_memories(
                    user_id, limit
                )
                memories["semantic"] = semantic
            
            # 获取记忆统计
            stats = await self.orchestrator.memory_manager.get_user_memory_stats(user_id)
            
            return {
                "user_id": user_id,
                "memories": memories,
                "statistics": stats,
                "retrieved_at": datetime.utcnow().isoformat()
            }
            
        except Exception as e:
            logger.error(f"获取记忆资源失败: {e}")
            return {"error": str(e)}
    
    async def _get_documents(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """获取文档资源"""
        try:
            user_id = params.get("user_id")
            limit = params.get("limit", 20)
            include_content = params.get("include_content", False)
            
            if user_id:
                # 获取特定用户的文档
                documents = await self.orchestrator.knowledge_processor.get_recent_documents(
                    user_id, limit
                )
            else:
                # 获取所有文档（需要管理员权限）
                documents = await self.orchestrator.db_manager.mongodb_client.get_recent_documents(
                    limit
                )
            
            # 如果不包含内容，移除content字段以减少数据量
            if not include_content:
                for doc in documents:
                    if "content" in doc:
                        doc["content_preview"] = doc["content"][:200] + "..."
                        del doc["content"]
            
            return {
                "user_id": user_id,
                "documents": documents,
                "total_count": len(documents),
                "include_content": include_content,
                "retrieved_at": datetime.utcnow().isoformat()
            }
            
        except Exception as e:
            logger.error(f"获取文档资源失败: {e}")
            return {"error": str(e)}
    
    async def _get_embeddings(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """获取向量嵌入资源"""
        try:
            user_id = params.get("user_id")
            collection_name = params.get("collection", "memories")
            limit = params.get("limit", 100)
            include_vectors = params.get("include_vectors", False)
            
            # 获取向量统计
            stats = await self.orchestrator.db_manager.chromadb_client.get_collection_stats(
                collection_name
            )
            
            # 获取文档元数据（不包含向量以减少数据量）
            documents = await self.orchestrator.db_manager.chromadb_client.get_documents(
                collection_name, user_id, limit, include_vectors
            )
            
            return {
                "user_id": user_id,
                "collection": collection_name,
                "documents": documents,
                "statistics": stats,
                "include_vectors": include_vectors,
                "retrieved_at": datetime.utcnow().isoformat()
            }
            
        except Exception as e:
            logger.error(f"获取向量嵌入资源失败: {e}")
            return {"error": str(e)}
    
    async def _get_graph_data(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """获取知识图谱资源"""
        try:
            user_id = params.get("user_id")
            node_type = params.get("node_type")
            limit = params.get("limit", 100)
            include_relationships = params.get("include_relationships", True)
            
            # 获取图谱统计
            if user_id:
                stats = await self.orchestrator.db_manager.neo4j_client.get_user_graph_stats(user_id)
            else:
                stats = await self.orchestrator.db_manager.neo4j_client.get_graph_stats()
            
            # 获取节点数据
            nodes = []
            relationships = []
            
            if user_id:
                # 获取用户相关的节点
                if not node_type or node_type == "concept":
                    concept_nodes = await self.orchestrator.db_manager.neo4j_client.get_user_concepts(
                        user_id, limit
                    )
                    nodes.extend(concept_nodes)
                
                if not node_type or node_type == "memory":
                    memory_nodes = await self.orchestrator.db_manager.neo4j_client.get_user_memories(
                        user_id, limit
                    )
                    nodes.extend(memory_nodes)
                
                if include_relationships:
                    relationships = await self.orchestrator.db_manager.neo4j_client.get_user_relationships(
                        user_id, limit
                    )
            
            return {
                "user_id": user_id,
                "node_type": node_type,
                "nodes": nodes,
                "relationships": relationships if include_relationships else [],
                "statistics": stats,
                "retrieved_at": datetime.utcnow().isoformat()
            }
            
        except Exception as e:
            logger.error(f"获取知识图谱资源失败: {e}")
            return {"error": str(e)}
    
    async def _get_user_context(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """获取用户上下文资源"""
        try:
            user_id = params.get("user_id")
            
            if not user_id:
                return {"error": "需要提供用户ID"}
            
            # 获取完整的用户上下文
            context = await self.orchestrator.get_user_context(user_id)
            
            return {
                "user_id": user_id,
                "context": context,
                "retrieved_at": datetime.utcnow().isoformat()
            }
            
        except Exception as e:
            logger.error(f"获取用户上下文资源失败: {e}")
            return {"error": str(e)}
    
    async def _get_system_stats(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """获取系统统计资源"""
        try:
            # 获取系统统计
            stats = await self.orchestrator.get_stats()
            
            return {
                "statistics": stats,
                "retrieved_at": datetime.utcnow().isoformat()
            }
            
        except Exception as e:
            logger.error(f"获取系统统计资源失败: {e}")
            return {"error": str(e)}
    
    async def _get_health_status(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """获取健康状态资源"""
        try:
            # 获取健康状态
            health = await self.orchestrator.health_check()
            
            return {
                "health_status": health,
                "checked_at": datetime.utcnow().isoformat()
            }
            
        except Exception as e:
            logger.error(f"获取健康状态资源失败: {e}")
            return {"error": str(e)}
    
    def get_resource_info(self, uri: str) -> Optional[Dict[str, Any]]:
        """获取资源信息"""
        return self.resources.get(uri)
    
    def remove_resource(self, uri: str) -> bool:
        """移除资源"""
        if uri in self.resources:
            del self.resources[uri]
            logger.debug(f"移除资源: {uri}")
            return True
        return False
    
    def get_resource_uris(self) -> List[str]:
        """获取所有资源URI"""
        return list(self.resources.keys())
    
    def get_resource_count(self) -> int:
        """获取资源数量"""
        return len(self.resources)
    
    async def subscribe_to_resource(self, uri: str, callback: callable) -> bool:
        """订阅资源更新（用于实时通知）"""
        # 这里可以实现资源订阅机制
        # 当资源发生变化时，调用callback通知客户端
        try:
            # 简化实现：记录订阅信息
            if not hasattr(self, '_subscribers'):
                self._subscribers = {}
            
            if uri not in self._subscribers:
                self._subscribers[uri] = []
            
            self._subscribers[uri].append(callback)
            
            logger.debug(f"订阅资源: {uri}")
            return True
            
        except Exception as e:
            logger.error(f"订阅资源失败: {uri} - {e}")
            return False
    
    async def unsubscribe_from_resource(self, uri: str, callback: callable) -> bool:
        """取消订阅资源"""
        try:
            if hasattr(self, '_subscribers') and uri in self._subscribers:
                if callback in self._subscribers[uri]:
                    self._subscribers[uri].remove(callback)
                    
                    # 如果没有订阅者了，删除该资源的订阅列表
                    if not self._subscribers[uri]:
                        del self._subscribers[uri]
                    
                    logger.debug(f"取消订阅资源: {uri}")
                    return True
            
            return False
            
        except Exception as e:
            logger.error(f"取消订阅资源失败: {uri} - {e}")
            return False
    
    async def notify_resource_change(self, uri: str, change_type: str, data: Any):
        """通知资源变化"""
        try:
            if hasattr(self, '_subscribers') and uri in self._subscribers:
                notification = {
                    "uri": uri,
                    "change_type": change_type,
                    "data": data,
                    "timestamp": datetime.utcnow().isoformat()
                }
                
                # 通知所有订阅者
                for callback in self._subscribers[uri]:
                    try:
                        await callback(notification)
                    except Exception as e:
                        logger.error(f"通知订阅者失败: {e}")
                
                logger.debug(f"通知资源变化: {uri} - {change_type}")
            
        except Exception as e:
            logger.error(f"通知资源变化失败: {uri} - {e}")